home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 008a / perl40_2.zip / TOKE.C < prev    next >
C/C++ Source or Header  |  1991-11-28  |  60KB  |  2,646 lines

  1. /* $RCSfile: toke.c,v $$Revision: 4.0.1.5 $$Date: 91/11/11 16:45:51 $
  2.  *
  3.  *    Copyright (c) 1991, Larry Wall
  4.  *
  5.  *    You may distribute under the terms of either the GNU General Public
  6.  *    License or the Artistic License, as specified in the README file.
  7.  *
  8.  * $Log:    toke.c,v $
  9.  * Revision 4.0.1.5  91/11/11  16:45:51  lwall
  10.  * patch19: default arg for shift was wrong after first subroutine definition
  11.  *
  12.  * Revision 4.0.1.4  91/11/05  19:02:48  lwall
  13.  * patch11: \x and \c were subject to double interpretation in regexps
  14.  * patch11: prepared for ctype implementations that don't define isascii()
  15.  * patch11: nested list operators could miscount parens
  16.  * patch11: once-thru blocks didn't display right in the debugger
  17.  * patch11: sort eval "whatever" didn't work
  18.  * patch11: underscore is now allowed within literal octal and hex numbers
  19.  *
  20.  * Revision 4.0.1.3  91/06/10  01:32:26  lwall
  21.  * patch10: m'$foo' now treats string as single quoted
  22.  * patch10: certain pattern optimizations were botched
  23.  *
  24.  * Revision 4.0.1.2  91/06/07  12:05:56  lwall
  25.  * patch4: new copyright notice
  26.  * patch4: debugger lost track of lines in eval
  27.  * patch4: //o and s///o now optimize themselves fully at runtime
  28.  * patch4: added global modifier for pattern matches
  29.  *
  30.  * Revision 4.0.1.1  91/04/12  09:18:18  lwall
  31.  * patch1: perl -de "print" wouldn't stop at the first statement
  32.  *
  33.  * Revision 4.0  91/03/20  01:42:14  lwall
  34.  * 4.0 baseline.
  35.  *
  36.  */
  37.  
  38.  
  39. #include "EXTERN.h"
  40. #include "perl.h"
  41. #include "perly.h"
  42.  
  43.  
  44. #ifdef I_FCNTL
  45. #include <fcntl.h>
  46. #endif
  47. #ifdef I_SYS_FILE
  48. #include <sys/file.h>
  49. #endif
  50.  
  51.  
  52. #ifdef f_next
  53. #undef f_next
  54. #endif
  55.  
  56.  
  57. /* which backslash sequences to keep in m// or s// */
  58.  
  59.  
  60. static char *patleave = "\\.^$@dDwWsSbB+*?|()-nrtfeaxc0123456789[{]}";
  61.  
  62.  
  63. char *reparse;        /* if non-null, scanident found ${foo[$bar]} */
  64.  
  65.  
  66. void checkcomma();
  67.  
  68.  
  69. #ifdef CLINE
  70. #undef CLINE
  71. #endif
  72. #define CLINE (cmdline = (curcmd->c_line < cmdline ? curcmd->c_line : cmdline))
  73.  
  74.  
  75. #define META(c) ((c) | 128)
  76.  
  77.  
  78. #define RETURN(retval) return (bufptr = s,(int)retval)
  79. #define OPERATOR(retval) return (expectterm = TRUE,bufptr = s,(int)retval)
  80. #define TERM(retval) return (CLINE, expectterm = FALSE,bufptr = s,(int)retval)
  81. #define LOOPX(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)LOOPEX)
  82. #define FTST(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)FILETEST)
  83. #define FUN0(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC0)
  84. #define FUN1(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC1)
  85. #define FUN2(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC2)
  86. #define FUN2x(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC2x)
  87. #define FUN3(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC3)
  88. #define FUN4(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC4)
  89. #define FUN5(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC5)
  90. #define FL(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FLIST)
  91. #define FL2(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FLIST2)
  92. #define HFUN(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)HSHFUN)
  93. #define HFUN3(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)HSHFUN3)
  94. #define LFUN(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)LVALFUN)
  95. #define AOP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)ADDOP)
  96. #define MOP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)MULOP)
  97. #define EOP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)EQOP)
  98. #define ROP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)RELOP)
  99. #define FOP(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP)
  100. #define FOP2(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP2)
  101. #define FOP3(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP3)
  102. #define FOP4(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP4)
  103. #define FOP22(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP22)
  104. #define FOP25(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP25)
  105.  
  106.  
  107. /* This bit of chicanery makes a unary function followed by
  108.  * a parenthesis into a function with one argument, highest precedence.
  109.  */
  110. #define UNI(f) return(yylval.ival = f,expectterm = TRUE,bufptr = s, \
  111.     (*s == '(' || (s = skipspace(s), *s == '(') ? (int)FUNC1 : (int)UNIOP) )
  112.  
  113.  
  114. /* This does similarly for list operators, merely by pretending that the
  115.  * paren came before the listop rather than after.
  116.  */
  117. #define LOP(f) return(CLINE, *s == '(' || (s = skipspace(s), *s == '(') ? \
  118.     (*s = (char) META('('), bufptr = oldbufptr, '(') : \
  119.     (yylval.ival=f,expectterm = TRUE,bufptr = s,(int)LISTOP))
  120. /* grandfather return to old style */
  121. #define OLDLOP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)LISTOP)
  122.  
  123.  
  124. char *
  125. skipspace(s)
  126. register char *s;
  127. {
  128.     while (s < bufend && isSPACE(*s))
  129.     s++;
  130.     return s;
  131. }
  132.  
  133.  
  134. #ifdef CRIPPLED_CC
  135.  
  136.  
  137. #undef UNI
  138. #undef LOP
  139. #define UNI(f) return uni(f,s)
  140. #define LOP(f) return lop(f,s)
  141.  
  142.  
  143. int
  144. uni(f,s)
  145. int f;
  146. char *s;
  147. {
  148.     yylval.ival = f;
  149.     expectterm = TRUE;
  150.     bufptr = s;
  151.     if (*s == '(')
  152.     return FUNC1;
  153.     s = skipspace(s);
  154.     if (*s == '(')
  155.     return FUNC1;
  156.     else
  157.     return UNIOP;
  158. }
  159.  
  160.  
  161. int
  162. lop(f,s)
  163. int f;
  164. char *s;
  165. {
  166.     CLINE;
  167.     if (*s != '(')
  168.     s = skipspace(s);
  169.     if (*s == '(') {
  170.     *s = META('(');
  171.     bufptr = oldbufptr;
  172.     return '(';
  173.     }
  174.     else {
  175.     yylval.ival=f;
  176.     expectterm = TRUE;
  177.     bufptr = s;
  178.     return LISTOP;
  179.     }
  180. }
  181.  
  182.  
  183. #endif /* CRIPPLED_CC */
  184.  
  185.  
  186. yylex()
  187. {
  188.     register char *s = bufptr;
  189.     register char *d;
  190.     register int tmp;
  191.     static bool in_format = FALSE;
  192.     static bool firstline = TRUE;
  193.     extern int yychar;        /* last token */
  194.  
  195.  
  196.     oldoldbufptr = oldbufptr;
  197.     oldbufptr = s;
  198.  
  199.  
  200.   retry:
  201. #ifdef YYDEBUG
  202.     if (debug & 1)
  203.     if (index(s,'\n'))
  204.         fprintf(stderr,"Tokener at %s",s);
  205.     else
  206.         fprintf(stderr,"Tokener at %s\n",s);
  207. #endif
  208. #ifdef BADSWITCH
  209.     if (*s & 128) {
  210.     if ((*s & 127) == '(') {
  211.         *s++ = '(';
  212.         oldbufptr = s;
  213.     }
  214.     else
  215.         warn("Unrecognized character \\%03o ignored", *s++ & 255);
  216.     goto retry;
  217.     }
  218. #endif
  219.     switch (*s) {
  220.     default:
  221.     if ((*s & 127) == '(') {
  222.         *s++ = '(';
  223.         oldbufptr = s;
  224.     }
  225.     else
  226.         warn("Unrecognized character \\%03o ignored", *s++ & 255);
  227.     goto retry;
  228.     case 4:
  229.     case 26:
  230.     goto fake_eof;            /* emulate EOF on ^D or ^Z */
  231.     case 0:
  232.     if (!rsfp)
  233.         RETURN(0);
  234.     if (s++ < bufend)
  235.         goto retry;            /* ignore stray nulls */
  236.     if (firstline) {
  237.         firstline = FALSE;
  238.         if (minus_n || minus_p || perldb) {
  239.         str_set(linestr,"");
  240.         if (perldb) {
  241.             char *getenv();
  242.             char *pdb = getenv("PERLDB");
  243.  
  244.  
  245.             str_cat(linestr, pdb ? pdb : "require 'perldb.pl'");
  246.             str_cat(linestr, ";");
  247.         }
  248.         if (minus_n || minus_p) {
  249.             str_cat(linestr,"line: while (<>) {");
  250.             if (minus_l)
  251.             str_cat(linestr,"chop;");
  252.             if (minus_a)
  253.             str_cat(linestr,"@F=split(' ');");
  254.         }
  255.         oldoldbufptr = oldbufptr = s = str_get(linestr);
  256.         bufend = linestr->str_ptr + linestr->str_cur;
  257.         goto retry;
  258.         }
  259.     }
  260.     if (in_format) {
  261.         bufptr = bufend;
  262.         yylval.formval = load_format();
  263.         in_format = FALSE;
  264.         oldoldbufptr = oldbufptr = s = str_get(linestr) + 1;
  265.         bufend = linestr->str_ptr + linestr->str_cur;
  266.         OPERATOR(FORMLIST);
  267.     }
  268.     curcmd->c_line++;
  269. #ifdef CRYPTSCRIPT
  270.     cryptswitch();
  271. #endif /* CRYPTSCRIPT */
  272.     do {
  273.         if ((s = str_gets(linestr, rsfp, 0)) == Nullch) {
  274.           fake_eof:
  275.         if (rsfp) {
  276.             if (preprocess)
  277.             (void)mypclose(rsfp);
  278.             else if ((FILE*)rsfp == stdin)
  279.             clearerr(stdin);
  280.             else
  281.             (void)fclose(rsfp);
  282.             rsfp = Nullfp;
  283.         }
  284.         if (minus_n || minus_p) {
  285.             str_set(linestr,minus_p ? ";}continue{print" : "");
  286.             str_cat(linestr,";}");
  287.             oldoldbufptr = oldbufptr = s = str_get(linestr);
  288.             bufend = linestr->str_ptr + linestr->str_cur;
  289.             minus_n = minus_p = 0;
  290.             goto retry;
  291.         }
  292.         oldoldbufptr = oldbufptr = s = str_get(linestr);
  293.         str_set(linestr,"");
  294.         RETURN(';');    /* not infinite loop because rsfp is NULL now */
  295.         }
  296.         if (doextract && *linestr->str_ptr == '#')
  297.         doextract = FALSE;
  298.     } while (doextract);
  299.     oldoldbufptr = oldbufptr = bufptr = s;
  300.     if (perldb) {
  301.         STR *str = Str_new(85,0);
  302.  
  303.  
  304.         str_sset(str,linestr);
  305.         astore(stab_xarray(curcmd->c_filestab),(int)curcmd->c_line,str);
  306.     }
  307. #ifdef DEBUG
  308.     if (firstline) {
  309.         char *showinput();
  310.         s = showinput();
  311.     }
  312. #endif
  313.     bufend = linestr->str_ptr + linestr->str_cur;
  314.     if (curcmd->c_line == 1) {
  315.         if (*s == '#' && s[1] == '!') {
  316.         if (!in_eval && !instr(s,"perl") && instr(origargv[0],"perl")) {
  317.             char **newargv;
  318.             char *cmd;
  319.  
  320.  
  321.             s += 2;
  322.             if (*s == ' ')
  323.             s++;
  324.             cmd = s;
  325.             while (s < bufend && !isSPACE(*s))
  326.             s++;
  327.             *s++ = '\0';
  328.             while (s < bufend && isSPACE(*s))
  329.             s++;
  330.             if (s < bufend) {
  331.             Newz(899,newargv,origargc+3,char*);
  332.             newargv[1] = s;
  333.             while (s < bufend && !isSPACE(*s))
  334.                 s++;
  335.             *s = '\0';
  336.             Copy(origargv+1, newargv+2, origargc+1, char*);
  337.             }
  338.             else
  339.             newargv = origargv;
  340.             newargv[0] = cmd;
  341.             execv(cmd,newargv);
  342.             fatal("Can't exec %s", cmd);
  343.         }
  344.         }
  345.         else {
  346.         while (s < bufend && isSPACE(*s))
  347.             s++;
  348.         if (*s == ':')    /* for csh's that have to exec sh scripts */
  349.             s++;
  350.         }
  351.     }
  352.     goto retry;
  353.     case ' ': case '\t': case '\f': case '\r': case 013:
  354.     s++;
  355.     goto retry;
  356.     case '#':
  357.     if (preprocess && s == str_get(linestr) &&
  358.            s[1] == ' ' && (isDIGIT(s[2]) || strnEQ(s+2,"line ",5)) ) {
  359.         while (*s && !isDIGIT(*s))
  360.         s++;
  361.         curcmd->c_line = atoi(s)-1;
  362.         while (isDIGIT(*s))
  363.         s++;
  364.         d = bufend;
  365.         while (s < d && isSPACE(*s)) s++;
  366.         s[strlen(s)-1] = '\0';    /* wipe out newline */
  367.         if (*s == '"') {
  368.         s++;
  369.         s[strlen(s)-1] = '\0';    /* wipe out trailing quote */
  370.         }
  371.         if (*s)
  372.         curcmd->c_filestab = fstab(s);
  373.         else
  374.         curcmd->c_filestab = fstab(origfilename);
  375.         oldoldbufptr = oldbufptr = s = str_get(linestr);
  376.     }
  377.     /* FALL THROUGH */
  378.     case '\n':
  379.     if (in_eval && !rsfp) {
  380.         d = bufend;
  381.         while (s < d && *s != '\n')
  382.         s++;
  383.         if (s < d)
  384.         s++;
  385.         if (in_format) {
  386.         bufptr = s;
  387.         yylval.formval = load_format();
  388.         in_format = FALSE;
  389.         oldoldbufptr = oldbufptr = s = bufptr + 1;
  390.         TERM(FORMLIST);
  391.         }
  392.         curcmd->c_line++;
  393.     }
  394.     else {
  395.         *s = '\0';
  396.         bufend = s;
  397.     }
  398.     goto retry;
  399.     case '-':
  400.     if (s[1] && isALPHA(s[1]) && !isALPHA(s[2])) {
  401.         s++;
  402.         switch (*s++) {
  403.         case 'r': FTST(O_FTEREAD);
  404.         case 'w': FTST(O_FTEWRITE);
  405.         case 'x': FTST(O_FTEEXEC);
  406.         case 'o': FTST(O_FTEOWNED);
  407.         case 'R': FTST(O_FTRREAD);
  408.         case 'W': FTST(O_FTRWRITE);
  409.         case 'X': FTST(O_FTREXEC);
  410.         case 'O': FTST(O_FTROWNED);
  411.         case 'e': FTST(O_FTIS);
  412.         case 'z': FTST(O_FTZERO);
  413.         case 's': FTST(O_FTSIZE);
  414.         case 'f': FTST(O_FTFILE);
  415.         case 'd': FTST(O_FTDIR);
  416.         case 'l': FTST(O_FTLINK);
  417.         case 'p': FTST(O_FTPIPE);
  418.         case 'S': FTST(O_FTSOCK);
  419.         case 'u': FTST(O_FTSUID);
  420.         case 'g': FTST(O_FTSGID);
  421.         case 'k': FTST(O_FTSVTX);
  422.         case 'b': FTST(O_FTBLK);
  423.         case 'c': FTST(O_FTCHR);
  424.         case 't': FTST(O_FTTTY);
  425.         case 'T': FTST(O_FTTEXT);
  426.         case 'B': FTST(O_FTBINARY);
  427.         case 'M': stabent("\024",TRUE); FTST(O_FTMTIME);
  428.         case 'A': stabent("\024",TRUE); FTST(O_FTATIME);
  429.         case 'C': stabent("\024",TRUE); FTST(O_FTCTIME);
  430.         default:
  431.         s -= 2;
  432.         break;
  433.         }
  434.     }
  435.     tmp = *s++;
  436.     if (*s == tmp) {
  437.         s++;
  438.         RETURN(DEC);
  439.     }
  440.     if (expectterm)
  441.         OPERATOR('-');
  442.     else
  443.         AOP(O_SUBTRACT);
  444.     case '+':
  445.     tmp = *s++;
  446.     if (*s == tmp) {
  447.         s++;
  448.         RETURN(INC);
  449.     }
  450.     if (expectterm)
  451.         OPERATOR('+');
  452.     else
  453.         AOP(O_ADD);
  454.  
  455.  
  456.     case '*':
  457.     if (expectterm) {
  458.         s = scanident(s,bufend,tokenbuf);
  459.         yylval.stabval = stabent(tokenbuf,TRUE);
  460.         TERM(STAR);
  461.     }
  462.     tmp = *s++;
  463.     if (*s == tmp) {
  464.         s++;
  465.         OPERATOR(POW);
  466.     }
  467.     MOP(O_MULTIPLY);
  468.     case '%':
  469.     if (expectterm) {
  470.         s = scanident(s,bufend,tokenbuf);
  471.         yylval.stabval = hadd(stabent(tokenbuf,TRUE));
  472.         TERM(HSH);
  473.     }
  474.     s++;
  475.     MOP(O_MODULO);
  476.  
  477.  
  478.     case '^':
  479.     case '~':
  480.     case '(':
  481.     case ',':
  482.     case ':':
  483.     case '[':
  484.     tmp = *s++;
  485.     OPERATOR(tmp);
  486.     case '{':
  487.     tmp = *s++;
  488.     yylval.ival = curcmd->c_line;
  489.     if (isSPACE(*s) || *s == '#')
  490.         cmdline = NOLINE;   /* invalidate current command line number */
  491.     OPERATOR(tmp);
  492.     case ';':
  493.     if (curcmd->c_line < cmdline)
  494.         cmdline = curcmd->c_line;
  495.     tmp = *s++;
  496.     OPERATOR(tmp);
  497.     case ')':
  498.     case ']':
  499.     tmp = *s++;
  500.     TERM(tmp);
  501.     case '}':
  502.     tmp = *s++;
  503.     RETURN(tmp);
  504.     case '&':
  505.     s++;
  506.     tmp = *s++;
  507.     if (tmp == '&')
  508.         OPERATOR(ANDAND);
  509.     s--;
  510.     if (expectterm) {
  511.         d = bufend;
  512.         while (s < d && isSPACE(*s))
  513.         s++;
  514.         if (isALPHA(*s) || *s == '_' || *s == '\'')
  515.         *(--s) = '\\';    /* force next ident to WORD */
  516.         OPERATOR(AMPER);
  517.     }
  518.     OPERATOR('&');
  519.     case '|':
  520.     s++;
  521.     tmp = *s++;
  522.     if (tmp == '|')
  523.         OPERATOR(OROR);
  524.     s--;
  525.     OPERATOR('|');
  526.     case '=':
  527.     s++;
  528.     tmp = *s++;
  529.     if (tmp == '=')
  530.         EOP(O_EQ);
  531.     if (tmp == '~')
  532.         OPERATOR(MATCH);
  533.     s--;
  534.     OPERATOR('=');
  535.     case '!':
  536.     s++;
  537.     tmp = *s++;
  538.     if (tmp == '=')
  539.         EOP(O_NE);
  540.     if (tmp == '~')
  541.         OPERATOR(NMATCH);
  542.     s--;
  543.     OPERATOR('!');
  544.     case '<':
  545.     if (expectterm) {
  546.         s = scanstr(s);
  547.         TERM(RSTRING);
  548.     }
  549.     s++;
  550.     tmp = *s++;
  551.     if (tmp == '<')
  552.         OPERATOR(LS);
  553.     if (tmp == '=') {
  554.         tmp = *s++;
  555.         if (tmp == '>')
  556.         EOP(O_NCMP);
  557.         s--;
  558.         ROP(O_LE);
  559.     }
  560.     s--;
  561.     ROP(O_LT);
  562.     case '>':
  563.     s++;
  564.     tmp = *s++;
  565.     if (tmp == '>')
  566.         OPERATOR(RS);
  567.     if (tmp == '=')
  568.         ROP(O_GE);
  569.     s--;
  570.     ROP(O_GT);
  571.  
  572.  
  573. #define SNARFWORD \
  574.     d = tokenbuf; \
  575.     while (isALNUM(*s) || *s == '\'') \
  576.         *d++ = *s++; \
  577.     while (d[-1] == '\'') \
  578.         d--,s--; \
  579.     *d = '\0'; \
  580.     d = tokenbuf;
  581.  
  582.  
  583.     case '$':
  584.     if (s[1] == '#' && (isALPHA(s[2]) || s[2] == '_')) {
  585.         s++;
  586.         s = scanident(s,bufend,tokenbuf);
  587.         yylval.stabval = aadd(stabent(tokenbuf,TRUE));
  588.         TERM(ARYLEN);
  589.     }
  590.     d = s;
  591.     s = scanident(s,bufend,tokenbuf);
  592.     if (reparse) {        /* turn ${foo[bar]} into ($foo[bar]) */
  593.       do_reparse:
  594.         s[-1] = ')';
  595.         s = d;
  596.         s[1] = s[0];
  597.         s[0] = '(';
  598.         goto retry;
  599.     }
  600.     yylval.stabval = stabent(tokenbuf,TRUE);
  601.     TERM(REG);
  602.  
  603.  
  604.     case '@':
  605.     d = s;
  606.     s = scanident(s,bufend,tokenbuf);
  607.     if (reparse)
  608.         goto do_reparse;
  609.     yylval.stabval = aadd(stabent(tokenbuf,TRUE));
  610.     TERM(ARY);
  611.  
  612.  
  613.     case '/':            /* may either be division or pattern */
  614.     case '?':            /* may either be conditional or pattern */
  615.     if (expectterm) {
  616.         s = scanpat(s);
  617.         TERM(PATTERN);
  618.     }
  619.     tmp = *s++;
  620.     if (tmp == '/')
  621.         MOP(O_DIVIDE);
  622.     OPERATOR(tmp);
  623.  
  624.  
  625.     case '.':
  626.     if (!expectterm || !isDIGIT(s[1])) {
  627.         tmp = *s++;
  628.         if (*s == tmp) {
  629.         s++;
  630.         OPERATOR(DOTDOT);
  631.         }
  632.         AOP(O_CONCAT);
  633.     }
  634.     /* FALL THROUGH */
  635.     case '0': case '1': case '2': case '3': case '4':
  636.     case '5': case '6': case '7': case '8': case '9':
  637.     case '\'': case '"': case '`':
  638.     s = scanstr(s);
  639.     TERM(RSTRING);
  640.  
  641.  
  642.     case '\\':    /* some magic to force next word to be a WORD */
  643.     s++;    /* used by do and sub to force a separate namespace */
  644.     /* FALL THROUGH */
  645.     case '_':
  646.     SNARFWORD;
  647.     if (d[1] == '_') {
  648.         if (strEQ(d,"__LINE__") || strEQ(d,"__FILE__")) {
  649.         ARG *arg = op_new(1);
  650.  
  651.  
  652.         yylval.arg = arg;
  653.         arg->arg_type = O_ITEM;
  654.         if (d[2] == 'L')
  655.             (void)sprintf(tokenbuf,"%ld",(long)curcmd->c_line);
  656.         else
  657.             strcpy(tokenbuf, stab_val(curcmd->c_filestab)->str_ptr);
  658.         arg[1].arg_type = A_SINGLE;
  659.         arg[1].arg_ptr.arg_str = str_make(tokenbuf,strlen(tokenbuf));
  660.         TERM(RSTRING);
  661.         }
  662.         else if (strEQ(d,"__END__")) {
  663. #ifndef TAINT
  664.         STAB *stab;
  665.         int fd;
  666.  
  667.  
  668.         /*SUPPRESS 560*/
  669.         if (stab = stabent("DATA",FALSE)) {
  670.             stab->str_pok |= SP_MULTI;
  671.             stab_io(stab) = stio_new();
  672.             stab_io(stab)->ifp = rsfp;
  673. #if defined(HAS_FCNTL) && defined(F_SETFD)
  674.             fd = fileno(rsfp);
  675.             fcntl(fd,F_SETFD,fd >= 3);
  676. #endif
  677.             if (preprocess)
  678.             stab_io(stab)->type = '|';
  679.             else if ((FILE*)rsfp == stdin)
  680.             stab_io(stab)->type = '-';
  681.             else
  682.             stab_io(stab)->type = '<';
  683.             rsfp = Nullfp;
  684.         }
  685. #endif
  686.         goto fake_eof;
  687.         }
  688.     }
  689.     break;
  690.     case 'a': case 'A':
  691.     SNARFWORD;
  692.     if (strEQ(d,"alarm"))
  693.         UNI(O_ALARM);
  694.     if (strEQ(d,"accept"))
  695.         FOP22(O_ACCEPT);
  696.     if (strEQ(d,"atan2"))
  697.         FUN2(O_ATAN2);
  698.     break;
  699.     case 'b': case 'B':
  700.     SNARFWORD;
  701.     if (strEQ(d,"bind"))
  702.         FOP2(O_BIND);
  703.     if (strEQ(d,"binmode"))
  704.         FOP(O_BINMODE);
  705.     break;
  706.     case 'c': case 'C':
  707.     SNARFWORD;
  708.     if (strEQ(d,"chop"))
  709.         LFUN(O_CHOP);
  710.     if (strEQ(d,"continue"))
  711.         OPERATOR(CONTINUE);
  712.     if (strEQ(d,"chdir")) {
  713.         (void)stabent("ENV",TRUE);    /* may use HOME */
  714.         UNI(O_CHDIR);
  715.     }
  716.     if (strEQ(d,"close"))
  717.         FOP(O_CLOSE);
  718.     if (strEQ(d,"closedir"))
  719.         FOP(O_CLOSEDIR);
  720.     if (strEQ(d,"cmp"))
  721.         EOP(O_SCMP);
  722.     if (strEQ(d,"caller"))
  723.         UNI(O_CALLER);
  724.     if (strEQ(d,"crypt")) {
  725. #ifdef FCRYPT
  726.         static int cryptseen = 0;
  727.  
  728.  
  729.         if (!cryptseen++)
  730.         init_des();
  731. #endif
  732.         FUN2(O_CRYPT);
  733.     }
  734.     if (strEQ(d,"chmod"))
  735.         LOP(O_CHMOD);
  736.     if (strEQ(d,"chown"))
  737.         LOP(O_CHOWN);
  738.     if (strEQ(d,"connect"))
  739.         FOP2(O_CONNECT);
  740.     if (strEQ(d,"cos"))
  741.         UNI(O_COS);
  742.     if (strEQ(d,"chroot"))
  743.         UNI(O_CHROOT);
  744.     break;
  745.     case 'd': case 'D':
  746.     SNARFWORD;
  747.     if (strEQ(d,"do")) {
  748.         d = bufend;
  749.         while (s < d && isSPACE(*s))
  750.         s++;
  751.         if (isALPHA(*s) || *s == '_')
  752.         *(--s) = '\\';    /* force next ident to WORD */
  753.         OPERATOR(DO);
  754.     }
  755.     if (strEQ(d,"die"))
  756.         LOP(O_DIE);
  757.     if (strEQ(d,"defined"))
  758.         LFUN(O_DEFINED);
  759.     if (strEQ(d,"delete"))
  760.         OPERATOR(DELETE);
  761.     if (strEQ(d,"dbmopen"))
  762.         HFUN3(O_DBMOPEN);
  763.     if (strEQ(d,"dbmclose"))
  764.         HFUN(O_DBMCLOSE);
  765.     if (strEQ(d,"dump"))
  766.         LOOPX(O_DUMP);
  767.     break;
  768.     case 'e': case 'E':
  769.     SNARFWORD;
  770.     if (strEQ(d,"else"))
  771.         OPERATOR(ELSE);
  772.     if (strEQ(d,"elsif")) {
  773.         yylval.ival = curcmd->c_line;
  774.         OPERATOR(ELSIF);
  775.     }
  776.     if (strEQ(d,"eq") || strEQ(d,"EQ"))
  777.         EOP(O_SEQ);
  778.     if (strEQ(d,"exit"))
  779.         UNI(O_EXIT);
  780.     if (strEQ(d,"eval")) {
  781.         allstabs = TRUE;        /* must initialize everything since */
  782.         UNI(O_EVAL);        /* we don't know what will be used */
  783.     }
  784.     if (strEQ(d,"eof"))
  785.         FOP(O_EOF);
  786.     if (strEQ(d,"exp"))
  787.         UNI(O_EXP);
  788.     if (strEQ(d,"each"))
  789.         HFUN(O_EACH);
  790.     if (strEQ(d,"exec")) {
  791.         set_csh();
  792.         LOP(O_EXEC_OP);
  793.     }
  794.     if (strEQ(d,"endhostent"))
  795.         FUN0(O_EHOSTENT);
  796.     if (strEQ(d,"endnetent"))
  797.         FUN0(O_ENETENT);
  798.     if (strEQ(d,"endservent"))
  799.         FUN0(O_ESERVENT);
  800.     if (strEQ(d,"endprotoent"))
  801.         FUN0(O_EPROTOENT);
  802.     if (strEQ(d,"endpwent"))
  803.         FUN0(O_EPWENT);
  804.     if (strEQ(d,"endgrent"))
  805.         FUN0(O_EGRENT);
  806.     break;
  807.     case 'f': case 'F':
  808.     SNARFWORD;
  809.     if (strEQ(d,"for") || strEQ(d,"foreach")) {
  810.         yylval.ival = curcmd->c_line;
  811.         OPERATOR(FOR);
  812.     }
  813.     if (strEQ(d,"format")) {
  814.         d = bufend;
  815.         while (s < d && isSPACE(*s))
  816.         s++;
  817.         if (isALPHA(*s) || *s == '_')
  818.         *(--s) = '\\';    /* force next ident to WORD */
  819.         in_format = TRUE;
  820.         allstabs = TRUE;        /* must initialize everything since */
  821.         OPERATOR(FORMAT);        /* we don't know what will be used */
  822.     }
  823.     if (strEQ(d,"fork"))
  824.         FUN0(O_FORK);
  825.     if (strEQ(d,"fcntl"))
  826.         FOP3(O_FCNTL);
  827.     if (strEQ(d,"fileno"))
  828.         FOP(O_FILENO);
  829.     if (strEQ(d,"flock"))
  830.         FOP2(O_FLOCK);
  831.     break;
  832.     case 'g': case 'G':
  833.     SNARFWORD;
  834.     if (strEQ(d,"gt") || strEQ(d,"GT"))
  835.         ROP(O_SGT);
  836.     if (strEQ(d,"ge") || strEQ(d,"GE"))
  837.         ROP(O_SGE);
  838.     if (strEQ(d,"grep"))
  839.         FL2(O_GREP);
  840.     if (strEQ(d,"goto"))
  841.         LOOPX(O_GOTO);
  842.     if (strEQ(d,"gmtime"))
  843.         UNI(O_GMTIME);
  844.     if (strEQ(d,"getc"))
  845.         FOP(O_GETC);
  846.     if (strnEQ(d,"get",3)) {
  847.         d += 3;
  848.         if (*d == 'p') {
  849.         if (strEQ(d,"ppid"))
  850.             FUN0(O_GETPPID);
  851.         if (strEQ(d,"pgrp"))
  852.             UNI(O_GETPGRP);
  853.         if (strEQ(d,"priority"))
  854.             FUN2(O_GETPRIORITY);
  855.         if (strEQ(d,"protobyname"))
  856.             UNI(O_GPBYNAME);
  857.         if (strEQ(d,"protobynumber"))
  858.             FUN1(O_GPBYNUMBER);
  859.         if (strEQ(d,"protoent"))
  860.             FUN0(O_GPROTOENT);
  861.         if (strEQ(d,"pwent"))
  862.             FUN0(O_GPWENT);
  863.         if (strEQ(d,"pwnam"))
  864.             FUN1(O_GPWNAM);
  865.         if (strEQ(d,"pwuid"))
  866.             FUN1(O_GPWUID);
  867.         if (strEQ(d,"peername"))
  868.             FOP(O_GETPEERNAME);
  869.         }
  870.         else if (*d == 'h') {
  871.         if (strEQ(d,"hostbyname"))
  872.             UNI(O_GHBYNAME);
  873.         if (strEQ(d,"hostbyaddr"))
  874.             FUN2(O_GHBYADDR);
  875.         if (strEQ(d,"hostent"))
  876.             FUN0(O_GHOSTENT);
  877.         }
  878.         else if (*d == 'n') {
  879.         if (strEQ(d,"netbyname"))
  880.             UNI(O_GNBYNAME);
  881.         if (strEQ(d,"netbyaddr"))
  882.             FUN2(O_GNBYADDR);
  883.         if (strEQ(d,"netent"))
  884.             FUN0(O_GNETENT);
  885.         }
  886.         else if (*d == 's') {
  887.         if (strEQ(d,"servbyname"))
  888.             FUN2(O_GSBYNAME);
  889.         if (strEQ(d,"servbyport"))
  890.             FUN2(O_GSBYPORT);
  891.         if (strEQ(d,"servent"))
  892.             FUN0(O_GSERVENT);
  893.         if (strEQ(d,"sockname"))
  894.             FOP(O_GETSOCKNAME);
  895.         if (strEQ(d,"sockopt"))
  896.             FOP3(O_GSOCKOPT);
  897.         }
  898.         else if (*d == 'g') {
  899.         if (strEQ(d,"grent"))
  900.             FUN0(O_GGRENT);
  901.         if (strEQ(d,"grnam"))
  902.             FUN1(O_GGRNAM);
  903.         if (strEQ(d,"grgid"))
  904.             FUN1(O_GGRGID);
  905.         }
  906.         else if (*d == 'l') {
  907.         if (strEQ(d,"login"))
  908.             FUN0(O_GETLOGIN);
  909.         }
  910.         d -= 3;
  911.     }
  912.     break;
  913.     case 'h': case 'H':
  914.     SNARFWORD;
  915.     if (strEQ(d,"hex"))
  916.         UNI(O_HEX);
  917.     break;
  918.     case 'i': case 'I':
  919.     SNARFWORD;
  920.     if (strEQ(d,"if")) {
  921.         yylval.ival = curcmd->c_line;
  922.         OPERATOR(IF);
  923.     }
  924.     if (strEQ(d,"index"))
  925.         FUN2x(O_INDEX);
  926.     if (strEQ(d,"int"))
  927.         UNI(O_INT);
  928.     if (strEQ(d,"ioctl"))
  929.         FOP3(O_IOCTL);
  930.     break;
  931.     case 'j': case 'J':
  932.     SNARFWORD;
  933.     if (strEQ(d,"join"))
  934.         FL2(O_JOIN);
  935.     break;
  936.     case 'k': case 'K':
  937.     SNARFWORD;
  938.     if (strEQ(d,"keys"))
  939.         HFUN(O_KEYS);
  940.     if (strEQ(d,"kill"))
  941.         LOP(O_KILL);
  942.     break;
  943.     case 'l': case 'L':
  944.     SNARFWORD;
  945.     if (strEQ(d,"last"))
  946.         LOOPX(O_LAST);
  947.     if (strEQ(d,"local"))
  948.         OPERATOR(LOCAL);
  949.     if (strEQ(d,"length"))
  950.         UNI(O_LENGTH);
  951.     if (strEQ(d,"lt") || strEQ(d,"LT"))
  952.         ROP(O_SLT);
  953.     if (strEQ(d,"le") || strEQ(d,"LE"))
  954.         ROP(O_SLE);
  955.     if (strEQ(d,"localtime"))
  956.         UNI(O_LOCALTIME);
  957.     if (strEQ(d,"log"))
  958.         UNI(O_LOG);
  959.     if (strEQ(d,"link"))
  960.         FUN2(O_LINK);
  961.     if (strEQ(d,"listen"))
  962.         FOP2(O_LISTEN);
  963.     if (strEQ(d,"lstat"))
  964.         FOP(O_LSTAT);
  965.     break;
  966.     case 'm': case 'M':
  967.     if (s[1] == '\'') {
  968.         d = "m";
  969.         s++;
  970.     }
  971.     else {
  972.         SNARFWORD;
  973.     }
  974.     if (strEQ(d,"m")) {
  975.         s = scanpat(s-1);
  976.         if (yylval.arg)
  977.         TERM(PATTERN);
  978.         else
  979.         RETURN(1);    /* force error */
  980.     }
  981.     switch (d[1]) {
  982.     case 'k':
  983.         if (strEQ(d,"mkdir"))
  984.         FUN2(O_MKDIR);
  985.         break;
  986.     case 's':
  987.         if (strEQ(d,"msgctl"))
  988.         FUN3(O_MSGCTL);
  989.         if (strEQ(d,"msgget"))
  990.         FUN2(O_MSGGET);
  991.         if (strEQ(d,"msgrcv"))
  992.         FUN5(O_MSGRCV);
  993.         if (strEQ(d,"msgsnd"))
  994.         FUN3(O_MSGSND);
  995.         break;
  996.     }
  997.     break;
  998.     case 'n': case 'N':
  999.     SNARFWORD;
  1000.     if (strEQ(d,"next"))
  1001.         LOOPX(O_NEXT);
  1002.     if (strEQ(d,"ne") || strEQ(d,"NE"))
  1003.         EOP(O_SNE);
  1004.     break;
  1005.     case 'o': case 'O':
  1006.     SNARFWORD;
  1007.     if (strEQ(d,"open"))
  1008.         OPERATOR(OPEN);
  1009.     if (strEQ(d,"ord"))
  1010.         UNI(O_ORD);
  1011.     if (strEQ(d,"oct"))
  1012.         UNI(O_OCT);
  1013.     if (strEQ(d,"opendir"))
  1014.         FOP2(O_OPEN_DIR);
  1015.     break;
  1016.     case 'p': case 'P':
  1017.     SNARFWORD;
  1018.     if (strEQ(d,"print")) {
  1019.         checkcomma(s,"filehandle");
  1020.         LOP(O_PRINT);
  1021.     }
  1022.     if (strEQ(d,"printf")) {
  1023.         checkcomma(s,"filehandle");
  1024.         LOP(O_PRTF);
  1025.     }
  1026.     if (strEQ(d,"push")) {
  1027.         yylval.ival = O_PUSH;
  1028.         OPERATOR(PUSH);
  1029.     }
  1030.     if (strEQ(d,"pop"))
  1031.         OPERATOR(POP);
  1032.     if (strEQ(d,"pack"))
  1033.         FL2(O_PACK);
  1034.     if (strEQ(d,"package"))
  1035.         OPERATOR(PACKAGE);
  1036.     if (strEQ(d,"pipe"))
  1037.         FOP22(O_PIPE);
  1038.     break;
  1039.     case 'q': case 'Q':
  1040.     SNARFWORD;
  1041.     if (strEQ(d,"q")) {
  1042.         s = scanstr(s-1);
  1043.         TERM(RSTRING);
  1044.     }
  1045.     if (strEQ(d,"qq")) {
  1046.         s = scanstr(s-2);
  1047.         TERM(RSTRING);
  1048.     }
  1049.     if (strEQ(d,"qx")) {
  1050.         s = scanstr(s-2);
  1051.         TERM(RSTRING);
  1052.     }
  1053.     break;
  1054.     case 'r': case 'R':
  1055.     SNARFWORD;
  1056.     if (strEQ(d,"return"))
  1057.         OLDLOP(O_RETURN);
  1058.     if (strEQ(d,"require")) {
  1059.         allstabs = TRUE;        /* must initialize everything since */
  1060.         UNI(O_REQUIRE);        /* we don't know what will be used */
  1061.     }
  1062.     if (strEQ(d,"reset"))
  1063.         UNI(O_RESET);
  1064.     if (strEQ(d,"redo"))
  1065.         LOOPX(O_REDO);
  1066.     if (strEQ(d,"rename"))
  1067.         FUN2(O_RENAME);
  1068.     if (strEQ(d,"rand"))
  1069.         UNI(O_RAND);
  1070.     if (strEQ(d,"rmdir"))
  1071.         UNI(O_RMDIR);
  1072.     if (strEQ(d,"rindex"))
  1073.         FUN2x(O_RINDEX);
  1074.     if (strEQ(d,"read"))
  1075.         FOP3(O_READ);
  1076.     if (strEQ(d,"readdir"))
  1077.         FOP(O_READDIR);
  1078.     if (strEQ(d,"rewinddir"))
  1079.         FOP(O_REWINDDIR);
  1080.     if (strEQ(d,"recv"))
  1081.         FOP4(O_RECV);
  1082.     if (strEQ(d,"reverse"))
  1083.         LOP(O_REVERSE);
  1084.     if (strEQ(d,"readlink"))
  1085.         UNI(O_READLINK);
  1086.     break;
  1087.     case 's': case 'S':
  1088.     if (s[1] == '\'') {
  1089.         d = "s";
  1090.         s++;
  1091.     }
  1092.     else {
  1093.         SNARFWORD;
  1094.     }
  1095.     if (strEQ(d,"s")) {
  1096.         s = scansubst(s);
  1097.         if (yylval.arg)
  1098.         TERM(SUBST);
  1099.         else
  1100.         RETURN(1);    /* force error */
  1101.     }
  1102.     switch (d[1]) {
  1103.     case 'a':
  1104.     case 'b':
  1105.         break;
  1106.     case 'c':
  1107.         if (strEQ(d,"scalar"))
  1108.         UNI(O_SCALAR);
  1109.         break;
  1110.     case 'd':
  1111.         break;
  1112.     case 'e':
  1113.         if (strEQ(d,"select"))
  1114.         OPERATOR(SSELECT);
  1115.         if (strEQ(d,"seek"))
  1116.         FOP3(O_SEEK);
  1117.         if (strEQ(d,"semctl"))
  1118.         FUN4(O_SEMCTL);
  1119.         if (strEQ(d,"semget"))
  1120.         FUN3(O_SEMGET);
  1121.         if (strEQ(d,"semop"))
  1122.         FUN2(O_SEMOP);
  1123.         if (strEQ(d,"send"))
  1124.         FOP3(O_SEND);
  1125.         if (strEQ(d,"setpgrp"))
  1126.         FUN2(O_SETPGRP);
  1127.         if (strEQ(d,"setpriority"))
  1128.         FUN3(O_SETPRIORITY);
  1129.         if (strEQ(d,"sethostent"))
  1130.         FUN1(O_SHOSTENT);
  1131.         if (strEQ(d,"setnetent"))
  1132.         FUN1(O_SNETENT);
  1133.         if (strEQ(d,"setservent"))
  1134.         FUN1(O_SSERVENT);
  1135.         if (strEQ(d,"setprotoent"))
  1136.         FUN1(O_SPROTOENT);
  1137.         if (strEQ(d,"setpwent"))
  1138.         FUN0(O_SPWENT);
  1139.         if (strEQ(d,"setgrent"))
  1140.         FUN0(O_SGRENT);
  1141.         if (strEQ(d,"seekdir"))
  1142.         FOP2(O_SEEKDIR);
  1143.         if (strEQ(d,"setsockopt"))
  1144.         FOP4(O_SSOCKOPT);
  1145.         break;
  1146.     case 'f':
  1147.     case 'g':
  1148.         break;
  1149.     case 'h':
  1150.         if (strEQ(d,"shift"))
  1151.         TERM(SHIFT);
  1152.         if (strEQ(d,"shmctl"))
  1153.         FUN3(O_SHMCTL);
  1154.         if (strEQ(d,"shmget"))
  1155.         FUN3(O_SHMGET);
  1156.         if (strEQ(d,"shmread"))
  1157.         FUN4(O_SHMREAD);
  1158.         if (strEQ(d,"shmwrite"))
  1159.         FUN4(O_SHMWRITE);
  1160.         if (strEQ(d,"shutdown"))
  1161.         FOP2(O_SHUTDOWN);
  1162.         break;
  1163.     case 'i':
  1164.         if (strEQ(d,"sin"))
  1165.         UNI(O_SIN);
  1166.         break;
  1167.     case 'j':
  1168.     case 'k':
  1169.         break;
  1170.     case 'l':
  1171.         if (strEQ(d,"sleep"))
  1172.         UNI(O_SLEEP);
  1173.         break;
  1174.     case 'm':
  1175.     case 'n':
  1176.         break;
  1177.     case 'o':
  1178.         if (strEQ(d,"socket"))
  1179.         FOP4(O_SOCKET);
  1180.         if (strEQ(d,"socketpair"))
  1181.         FOP25(O_SOCKPAIR);
  1182.         if (strEQ(d,"sort")) {
  1183.         checkcomma(s,"subroutine name");
  1184.         d = bufend;
  1185.         while (s < d && isSPACE(*s)) s++;
  1186.         if (*s == ';' || *s == ')')        /* probably a close */
  1187.             fatal("sort is now a reserved word");
  1188.         if (isALPHA(*s) || *s == '_') {
  1189.             /*SUPPRESS 530*/
  1190.             for (d = s; isALNUM(*d); d++) ;
  1191.             strncpy(tokenbuf,s,d-s);
  1192.             if (strNE(tokenbuf,"keys") &&
  1193.             strNE(tokenbuf,"values") &&
  1194.             strNE(tokenbuf,"split") &&
  1195.             strNE(tokenbuf,"grep") &&
  1196.             strNE(tokenbuf,"readdir") &&
  1197.             strNE(tokenbuf,"unpack") &&
  1198.             strNE(tokenbuf,"do") &&
  1199.             strNE(tokenbuf,"eval") &&
  1200.             (d >= bufend || isSPACE(*d)) )
  1201.             *(--s) = '\\';    /* force next ident to WORD */
  1202.         }
  1203.         LOP(O_SORT);
  1204.         }
  1205.         break;
  1206.     case 'p':
  1207.         if (strEQ(d,"split"))
  1208.         TERM(SPLIT);
  1209.         if (strEQ(d,"sprintf"))
  1210.         FL(O_SPRINTF);
  1211.         if (strEQ(d,"splice")) {
  1212.         yylval.ival = O_SPLICE;
  1213.         OPERATOR(PUSH);
  1214.         }
  1215.         break;
  1216.     case 'q':
  1217.         if (strEQ(d,"sqrt"))
  1218.         UNI(O_SQRT);
  1219.         break;
  1220.     case 'r':
  1221.         if (strEQ(d,"srand"))
  1222.         UNI(O_SRAND);
  1223.         break;
  1224.     case 's':
  1225.         break;
  1226.     case 't':
  1227.         if (strEQ(d,"stat"))
  1228.         FOP(O_STAT);
  1229.         if (strEQ(d,"study")) {
  1230.         sawstudy++;
  1231.         LFUN(O_STUDY);
  1232.         }
  1233.         break;
  1234.     case 'u':
  1235.         if (strEQ(d,"substr"))
  1236.         FUN2x(O_SUBSTR);
  1237.         if (strEQ(d,"sub")) {
  1238.         yylval.ival = savestack->ary_fill; /* restore stuff on reduce */
  1239.         savelong(&subline);
  1240.         saveitem(subname);
  1241.  
  1242.  
  1243.         subline = curcmd->c_line;
  1244.         d = bufend;
  1245.         while (s < d && isSPACE(*s))
  1246.             s++;
  1247.         if (isALPHA(*s) || *s == '_' || *s == '\'') {
  1248.             str_sset(subname,curstname);
  1249.             str_ncat(subname,"'",1);
  1250.             for (d = s+1; isALNUM(*d) || *d == '\''; d++)
  1251.             /*SUPPRESS 530*/
  1252.             ;
  1253.             if (d[-1] == '\'')
  1254.             d--;
  1255.             str_ncat(subname,s,d-s);
  1256.             *(--s) = '\\';    /* force next ident to WORD */
  1257.         }
  1258.         else
  1259.             str_set(subname,"?");
  1260.         OPERATOR(SUB);
  1261.         }
  1262.         break;
  1263.     case 'v':
  1264.     case 'w':
  1265.     case 'x':
  1266.         break;
  1267.     case 'y':
  1268.         if (strEQ(d,"system")) {
  1269.         set_csh();
  1270.         LOP(O_SYSTEM);
  1271.         }
  1272.         if (strEQ(d,"symlink"))
  1273.         FUN2(O_SYMLINK);
  1274.         if (strEQ(d,"syscall"))
  1275.         LOP(O_SYSCALL);
  1276.         if (strEQ(d,"sysread"))
  1277.         FOP3(O_SYSREAD);
  1278.         if (strEQ(d,"syswrite"))
  1279.         FOP3(O_SYSWRITE);
  1280.         break;
  1281.     case 'z':
  1282.         break;
  1283.     }
  1284.     break;
  1285.     case 't': case 'T':
  1286.     SNARFWORD;
  1287.     if (strEQ(d,"tr")) {
  1288.         s = scantrans(s);
  1289.         if (yylval.arg)
  1290.         TERM(TRANS);
  1291.         else
  1292.         RETURN(1);    /* force error */
  1293.     }
  1294.     if (strEQ(d,"tell"))
  1295.         FOP(O_TELL);
  1296.     if (strEQ(d,"telldir"))
  1297.         FOP(O_TELLDIR);
  1298.     if (strEQ(d,"time"))
  1299.         FUN0(O_TIME);
  1300.     if (strEQ(d,"times"))
  1301.         FUN0(O_TMS);
  1302.     if (strEQ(d,"truncate"))
  1303.         FOP2(O_TRUNCATE);
  1304.     break;
  1305.     case 'u': case 'U':
  1306.     SNARFWORD;
  1307.     if (strEQ(d,"using"))
  1308.         OPERATOR(USING);
  1309.     if (strEQ(d,"until")) {
  1310.         yylval.ival = curcmd->c_line;
  1311.         OPERATOR(UNTIL);
  1312.     }
  1313.     if (strEQ(d,"unless")) {
  1314.         yylval.ival = curcmd->c_line;
  1315.         OPERATOR(UNLESS);
  1316.     }
  1317.     if (strEQ(d,"unlink"))
  1318.         LOP(O_UNLINK);
  1319.     if (strEQ(d,"undef"))
  1320.         LFUN(O_UNDEF);
  1321.     if (strEQ(d,"unpack"))
  1322.         FUN2(O_UNPACK);
  1323.     if (strEQ(d,"utime"))
  1324.         LOP(O_UTIME);
  1325.     if (strEQ(d,"umask"))
  1326.         UNI(O_UMASK);
  1327.     if (strEQ(d,"unshift")) {
  1328.         yylval.ival = O_UNSHIFT;
  1329.         OPERATOR(PUSH);
  1330.     }
  1331.     break;
  1332.     case 'v': case 'V':
  1333.     SNARFWORD;
  1334.     if (strEQ(d,"values"))
  1335.         HFUN(O_VALUES);
  1336.     if (strEQ(d,"vec")) {
  1337.         sawvec = TRUE;
  1338.         FUN3(O_VEC);
  1339.     }
  1340.     break;
  1341.     case 'w': case 'W':
  1342.     SNARFWORD;
  1343.     if (strEQ(d,"while")) {
  1344.         yylval.ival = curcmd->c_line;
  1345.         OPERATOR(WHILE);
  1346.     }
  1347.     if (strEQ(d,"warn"))
  1348.         LOP(O_WARN);
  1349.     if (strEQ(d,"wait"))
  1350.         FUN0(O_WAIT);
  1351.     if (strEQ(d,"waitpid"))
  1352.         FUN2(O_WAITPID);
  1353.     if (strEQ(d,"wantarray")) {
  1354.         yylval.arg = op_new(1);
  1355.         yylval.arg->arg_type = O_ITEM;
  1356.         yylval.arg[1].arg_type = A_WANTARRAY;
  1357.         TERM(RSTRING);
  1358.     }
  1359.     if (strEQ(d,"write"))
  1360.         FOP(O_WRITE);
  1361.     break;
  1362.     case 'x': case 'X':
  1363.     SNARFWORD;
  1364.     if (!expectterm && strEQ(d,"x"))
  1365.         MOP(O_REPEAT);
  1366.     break;
  1367.     case 'y': case 'Y':
  1368.     if (s[1] == '\'') {
  1369.         d = "y";
  1370.         s++;
  1371.     }
  1372.     else {
  1373.         SNARFWORD;
  1374.     }
  1375.     if (strEQ(d,"y")) {
  1376.         s = scantrans(s);
  1377.         TERM(TRANS);
  1378.     }
  1379.     break;
  1380.     case 'z': case 'Z':
  1381.     SNARFWORD;
  1382.     break;
  1383.     }
  1384.     yylval.cval = savestr(d);
  1385.     expectterm = FALSE;
  1386.     if (oldoldbufptr && oldoldbufptr < bufptr) {
  1387.     while (isSPACE(*oldoldbufptr))
  1388.         oldoldbufptr++;
  1389.     if (*oldoldbufptr == 'p' && strnEQ(oldoldbufptr,"print",5))
  1390.         expectterm = TRUE;
  1391.     else if (*oldoldbufptr == 's' && strnEQ(oldoldbufptr,"sort",4))
  1392.         expectterm = TRUE;
  1393.     }
  1394.     return (CLINE, bufptr = s, (int)WORD);
  1395. }
  1396.  
  1397.  
  1398. void
  1399. checkcomma(s,what)
  1400. register char *s;
  1401. char *what;
  1402. {
  1403.     char *someword;
  1404.  
  1405.  
  1406.     if (*s == '(')
  1407.     s++;
  1408.     while (s < bufend && isSPACE(*s))
  1409.     s++;
  1410.     if (isALPHA(*s) || *s == '_') {
  1411.     someword = s++;
  1412.     while (isALNUM(*s))
  1413.         s++;
  1414.     while (s < bufend && isSPACE(*s))
  1415.         s++;
  1416.     if (*s == ',') {
  1417.         *s = '\0';
  1418.         someword = instr(
  1419.           "tell eof times getlogin wait length shift umask getppid \
  1420.           cos exp int log rand sin sqrt ord wantarray",
  1421.           someword);
  1422.         *s = ',';
  1423.         if (someword)
  1424.         return;
  1425.         fatal("No comma allowed after %s", what);
  1426.     }
  1427.     }
  1428. }
  1429.  
  1430.  
  1431. char *
  1432. scanident(s,send,dest)
  1433. register char *s;
  1434. register char *send;
  1435. char *dest;
  1436. {
  1437.     register char *d;
  1438.     int brackets = 0;
  1439.  
  1440.  
  1441.     reparse = Nullch;
  1442.     s++;
  1443.     d = dest;
  1444.     if (isDIGIT(*s)) {
  1445.     while (isDIGIT(*s))
  1446.         *d++ = *s++;
  1447.     }
  1448.     else {
  1449.     while (isALNUM(*s) || *s == '\'')
  1450.         *d++ = *s++;
  1451.     }
  1452.     while (d > dest+1 && d[-1] == '\'')
  1453.     d--,s--;
  1454.     *d = '\0';
  1455.     d = dest;
  1456.     if (!*d) {
  1457.     *d = *s++;
  1458.     if (*d == '{' /* } */ ) {
  1459.         d = dest;
  1460.         brackets++;
  1461.         while (s < send && brackets) {
  1462.         if (!reparse && (d == dest || (*s && isALNUM(*s) ))) {
  1463.             *d++ = *s++;
  1464.             continue;
  1465.         }
  1466.         else if (!reparse)
  1467.             reparse = s;
  1468.         switch (*s++) {
  1469.         /* { */
  1470.         case '}':
  1471.             brackets--;
  1472.             if (reparse && reparse == s - 1)
  1473.             reparse = Nullch;
  1474.             break;
  1475.         case '{':   /* } */
  1476.             brackets++;
  1477.             break;
  1478.         }
  1479.         }
  1480.         *d = '\0';
  1481.         d = dest;
  1482.     }
  1483.     else
  1484.         d[1] = '\0';
  1485.     }
  1486.     if (*d == '^' && (isUPPER(*s) || index("[\\]^_?", *s))) {
  1487. #ifdef DEBUGGING
  1488.     if (*s == 'D')
  1489.         debug |= 32768;
  1490. #endif
  1491.     *d = *s++ ^ 64;
  1492.     }
  1493.     return s;
  1494. }
  1495.  
  1496.  
  1497. void
  1498. scanconst(spat,string,len)
  1499. SPAT *spat;
  1500. char *string;
  1501. int len;
  1502. {
  1503.     register STR *tmpstr;
  1504.     register char *t;
  1505.     register char *d;
  1506.     register char *e;
  1507.     char *origstring = string;
  1508.     static char *vert = "|";
  1509.  
  1510.  
  1511.     if (ninstr(string, string+len, vert, vert+1))
  1512.     return;
  1513.     if (*string == '^')
  1514.     string++, len--;
  1515.     tmpstr = Str_new(86,len);
  1516.     str_nset(tmpstr,string,len);
  1517.     t = str_get(tmpstr);
  1518.     e = t + len;
  1519.     tmpstr->str_u.str_useful = 100;
  1520.     for (d=t; d < e; ) {
  1521.     switch (*d) {
  1522.     case '{':
  1523.         if (isDIGIT(d[1]))
  1524.         e = d;
  1525.         else
  1526.         goto defchar;
  1527.         break;
  1528.     case '.': case '[': case '$': case '(': case ')': case '|': case '+':
  1529.     case '^':
  1530.         e = d;
  1531.         break;
  1532.     case '\\':
  1533.         if (d[1] && index("wWbB0123456789sSdDlLuUExc",d[1])) {
  1534.         e = d;
  1535.         break;
  1536.         }
  1537.         (void)bcopy(d+1,d,e-d);
  1538.         e--;
  1539.         switch(*d) {
  1540.         case 'n':
  1541.         *d = '\n';
  1542.         break;
  1543.         case 't':
  1544.         *d = '\t';
  1545.         break;
  1546.         case 'f':
  1547.         *d = '\f';
  1548.         break;
  1549.         case 'r':
  1550.         *d = '\r';
  1551.         break;
  1552.         case 'e':
  1553.         *d = '\033';
  1554.         break;
  1555.         case 'a':
  1556.         *d = '\007';
  1557.         break;
  1558.         }
  1559.         /* FALL THROUGH */
  1560.     default:
  1561.       defchar:
  1562.         if (d[1] == '*' || (d[1] == '{' && d[2] == '0') || d[1] == '?') {
  1563.         e = d;
  1564.         break;
  1565.         }
  1566.         d++;
  1567.     }
  1568.     }
  1569.     if (d == t) {
  1570.     str_free(tmpstr);
  1571.     return;
  1572.     }
  1573.     *d = '\0';
  1574.     tmpstr->str_cur = d - t;
  1575.     if (d == t+len)
  1576.     spat->spat_flags |= SPAT_ALL;
  1577.     if (*origstring != '^')
  1578.     spat->spat_flags |= SPAT_SCANFIRST;
  1579.     spat->spat_short = tmpstr;
  1580.     spat->spat_slen = d - t;
  1581. }
  1582.  
  1583.  
  1584. char *
  1585. scanpat(s)
  1586. register char *s;
  1587. {
  1588.     register SPAT *spat;
  1589.     register char *d;
  1590.     register char *e;
  1591.     int len;
  1592.     SPAT savespat;
  1593.     STR *str = Str_new(93,0);
  1594.     char delim;
  1595.  
  1596.  
  1597.     Newz(801,spat,1,SPAT);
  1598.     spat->spat_next = curstash->tbl_spatroot;    /* link into spat list */
  1599.     curstash->tbl_spatroot = spat;
  1600.  
  1601.  
  1602.     switch (*s++) {
  1603.     case 'm':
  1604.     s++;
  1605.     break;
  1606.     case '/':
  1607.     break;
  1608.     case '?':
  1609.     spat->spat_flags |= SPAT_ONCE;
  1610.     break;
  1611.     default:
  1612.     fatal("panic: scanpat");
  1613.     }
  1614.     s = str_append_till(str,s,bufend,s[-1],patleave);
  1615.     if (s >= bufend) {
  1616.     str_free(str);
  1617.     yyerror("Search pattern not terminated");
  1618.     yylval.arg = Nullarg;
  1619.     return s;
  1620.     }
  1621.     delim = *s++;
  1622.     while (*s == 'i' || *s == 'o' || *s == 'g') {
  1623.     if (*s == 'i') {
  1624.         s++;
  1625.         sawi = TRUE;
  1626.         spat->spat_flags |= SPAT_FOLD;
  1627.     }
  1628.     if (*s == 'o') {
  1629.         s++;
  1630.         spat->spat_flags |= SPAT_KEEP;
  1631.     }
  1632.     if (*s == 'g') {
  1633.         s++;
  1634.         spat->spat_flags |= SPAT_GLOBAL;
  1635.     }
  1636.     }
  1637.     len = str->str_cur;
  1638.     e = str->str_ptr + len;
  1639.     if (delim == '\'')
  1640.     d = e;
  1641.     else
  1642.     d = str->str_ptr;
  1643.     for (; d < e; d++) {
  1644.     if (*d == '\\')
  1645.         d++;
  1646.     else if ((*d == '$' && d[1] && d[1] != '|' && d[1] != ')') ||
  1647.          (*d == '@')) {
  1648.         register ARG *arg;
  1649.  
  1650.  
  1651.         spat->spat_runtime = arg = op_new(1);
  1652.         arg->arg_type = O_ITEM;
  1653.         arg[1].arg_type = A_DOUBLE;
  1654.         arg[1].arg_ptr.arg_str = str_smake(str);
  1655.         d = scanident(d,bufend,buf);
  1656.         (void)stabent(buf,TRUE);        /* make sure it's created */
  1657.         for (; d < e; d++) {
  1658.         if (*d == '\\')
  1659.             d++;
  1660.         else if (*d == '$' && d[1] && d[1] != '|' && d[1] != ')') {
  1661.             d = scanident(d,bufend,buf);
  1662.             (void)stabent(buf,TRUE);
  1663.         }
  1664.         else if (*d == '@') {
  1665.             d = scanident(d,bufend,buf);
  1666.             if (strEQ(buf,"ARGV") || strEQ(buf,"ENV") ||
  1667.               strEQ(buf,"SIG") || strEQ(buf,"INC"))
  1668.             (void)stabent(buf,TRUE);
  1669.         }
  1670.         }
  1671.         goto got_pat;        /* skip compiling for now */
  1672.     }
  1673.     }
  1674.     if (spat->spat_flags & SPAT_FOLD)
  1675. #ifdef STRUCTCOPY
  1676.     savespat = *spat;
  1677. #else
  1678.     (void)bcopy((char *)spat, (char *)&savespat, sizeof(SPAT));
  1679. #endif
  1680.     scanconst(spat,str->str_ptr,len);
  1681.     if ((spat->spat_flags & SPAT_ALL) && (spat->spat_flags & SPAT_SCANFIRST)) {
  1682.     fbmcompile(spat->spat_short, spat->spat_flags & SPAT_FOLD);
  1683.     spat->spat_regexp = regcomp(str->str_ptr,str->str_ptr+len,
  1684.         spat->spat_flags & SPAT_FOLD);
  1685.         /* Note that this regexp can still be used if someone says
  1686.          * something like /a/ && s//b/;  so we can't delete it.
  1687.          */
  1688.     }
  1689.     else {
  1690.     if (spat->spat_flags & SPAT_FOLD)
  1691. #ifdef STRUCTCOPY
  1692.         *spat = savespat;
  1693. #else
  1694.         (void)bcopy((char *)&savespat, (char *)spat, sizeof(SPAT));
  1695. #endif
  1696.     if (spat->spat_short)
  1697.         fbmcompile(spat->spat_short, spat->spat_flags & SPAT_FOLD);
  1698.     spat->spat_regexp = regcomp(str->str_ptr,str->str_ptr+len,
  1699.         spat->spat_flags & SPAT_FOLD);
  1700.     hoistmust(spat);
  1701.     }
  1702.   got_pat:
  1703.     str_free(str);
  1704.     yylval.arg = make_match(O_MATCH,stab2arg(A_STAB,defstab),spat);
  1705.     return s;
  1706. }
  1707.  
  1708.  
  1709. char *
  1710. scansubst(s)
  1711. register char *s;
  1712. {
  1713.     register SPAT *spat;
  1714.     register char *d;
  1715.     register char *e;
  1716.     int len;
  1717.     STR *str = Str_new(93,0);
  1718.  
  1719.  
  1720.     Newz(802,spat,1,SPAT);
  1721.     spat->spat_next = curstash->tbl_spatroot;    /* link into spat list */
  1722.     curstash->tbl_spatroot = spat;
  1723.  
  1724.  
  1725.     s = str_append_till(str,s+1,bufend,*s,patleave);
  1726.     if (s >= bufend) {
  1727.     str_free(str);
  1728.     yyerror("Substitution pattern not terminated");
  1729.     yylval.arg = Nullarg;
  1730.     return s;
  1731.     }
  1732.     len = str->str_cur;
  1733.     e = str->str_ptr + len;
  1734.     for (d = str->str_ptr; d < e; d++) {
  1735.     if (*d == '\\')
  1736.         d++;
  1737.     else if ((*d == '$' && d[1] && d[1] != '|' && /*(*/ d[1] != ')') ||
  1738.         *d == '@' ) {
  1739.         register ARG *arg;
  1740.  
  1741.  
  1742.         spat->spat_runtime = arg = op_new(1);
  1743.         arg->arg_type = O_ITEM;
  1744.         arg[1].arg_type = A_DOUBLE;
  1745.         arg[1].arg_ptr.arg_str = str_smake(str);
  1746.         d = scanident(d,e,buf);
  1747.         (void)stabent(buf,TRUE);        /* make sure it's created */
  1748.         for (; *d; d++) {
  1749.         if (*d == '$' && d[1] && d[-1] != '\\' && d[1] != '|') {
  1750.             d = scanident(d,e,buf);
  1751.             (void)stabent(buf,TRUE);
  1752.         }
  1753.         else if (*d == '@' && d[-1] != '\\') {
  1754.             d = scanident(d,e,buf);
  1755.             if (strEQ(buf,"ARGV") || strEQ(buf,"ENV") ||
  1756.               strEQ(buf,"SIG") || strEQ(buf,"INC"))
  1757.             (void)stabent(buf,TRUE);
  1758.         }
  1759.         }
  1760.         goto get_repl;        /* skip compiling for now */
  1761.     }
  1762.     }
  1763.     scanconst(spat,str->str_ptr,len);
  1764. get_repl:
  1765.     s = scanstr(s);
  1766.     if (s >= bufend) {
  1767.     str_free(str);
  1768.     yyerror("Substitution replacement not terminated");
  1769.     yylval.arg = Nullarg;
  1770.     return s;
  1771.     }
  1772.     spat->spat_repl = yylval.arg;
  1773.     if ((spat->spat_repl[1].arg_type & A_MASK) == A_SINGLE)
  1774.     spat->spat_flags |= SPAT_CONST;
  1775.     else if ((spat->spat_repl[1].arg_type & A_MASK) == A_DOUBLE) {
  1776.     STR *tmpstr;
  1777.     register char *t;
  1778.  
  1779.  
  1780.     spat->spat_flags |= SPAT_CONST;
  1781.     tmpstr = spat->spat_repl[1].arg_ptr.arg_str;
  1782.     e = tmpstr->str_ptr + tmpstr->str_cur;
  1783.     for (t = tmpstr->str_ptr; t < e; t++) {
  1784.         if (*t == '$' && t[1] && (index("`'&+0123456789",t[1]) ||
  1785.           (t[1] == '{' /*}*/ && isDIGIT(t[2])) ))
  1786.         spat->spat_flags &= ~SPAT_CONST;
  1787.     }
  1788.     }
  1789.     while (*s == 'g' || *s == 'i' || *s == 'e' || *s == 'o') {
  1790.     if (*s == 'e') {
  1791.         s++;
  1792.         if ((spat->spat_repl[1].arg_type & A_MASK) == A_DOUBLE)
  1793.         spat->spat_repl[1].arg_type = A_SINGLE;
  1794.         spat->spat_repl = make_op(
  1795.         (spat->spat_repl[1].arg_type == A_SINGLE ? O_EVALONCE : O_EVAL),
  1796.         2,
  1797.         spat->spat_repl,
  1798.         Nullarg,
  1799.         Nullarg);
  1800.         spat->spat_flags &= ~SPAT_CONST;
  1801.     }
  1802.     if (*s == 'g') {
  1803.         s++;
  1804.         spat->spat_flags |= SPAT_GLOBAL;
  1805.     }
  1806.     if (*s == 'i') {
  1807.         s++;
  1808.         sawi = TRUE;
  1809.         spat->spat_flags |= SPAT_FOLD;
  1810.         if (!(spat->spat_flags & SPAT_SCANFIRST)) {
  1811.         str_free(spat->spat_short);    /* anchored opt doesn't do */
  1812.         spat->spat_short = Nullstr;    /* case insensitive match */
  1813.         spat->spat_slen = 0;
  1814.         }
  1815.     }
  1816.     if (*s == 'o') {
  1817.         s++;
  1818.         spat->spat_flags |= SPAT_KEEP;
  1819.     }
  1820.     }
  1821.     if (spat->spat_short && (spat->spat_flags & SPAT_SCANFIRST))
  1822.     fbmcompile(spat->spat_short, spat->spat_flags & SPAT_FOLD);
  1823.     if (!spat->spat_runtime) {
  1824.     spat->spat_regexp = regcomp(str->str_ptr,str->str_ptr+len,
  1825.       spat->spat_flags & SPAT_FOLD);
  1826.     hoistmust(spat);
  1827.     }
  1828.     yylval.arg = make_match(O_SUBST,stab2arg(A_STAB,defstab),spat);
  1829.     str_free(str);
  1830.     return s;
  1831. }
  1832.  
  1833.  
  1834. void
  1835. hoistmust(spat)
  1836. register SPAT *spat;
  1837. {
  1838.     if (!spat->spat_short && spat->spat_regexp->regstart &&
  1839.     (!spat->spat_regexp->regmust || spat->spat_regexp->reganch & ROPT_ANCH)
  1840.        ) {
  1841.     if (!(spat->spat_regexp->reganch & ROPT_ANCH))
  1842.         spat->spat_flags |= SPAT_SCANFIRST;
  1843.     else if (spat->spat_flags & SPAT_FOLD)
  1844.         return;
  1845.     spat->spat_short = str_smake(spat->spat_regexp->regstart);
  1846.     }
  1847.     else if (spat->spat_regexp->regmust) {/* is there a better short-circuit? */
  1848.     if (spat->spat_short &&
  1849.       str_eq(spat->spat_short,spat->spat_regexp->regmust))
  1850.     {
  1851.         if (spat->spat_flags & SPAT_SCANFIRST) {
  1852.         str_free(spat->spat_short);
  1853.         spat->spat_short = Nullstr;
  1854.         }
  1855.         else {
  1856.         str_free(spat->spat_regexp->regmust);
  1857.         spat->spat_regexp->regmust = Nullstr;
  1858.         return;
  1859.         }
  1860.     }
  1861.     if (!spat->spat_short ||    /* promote the better string */
  1862.       ((spat->spat_flags & SPAT_SCANFIRST) &&
  1863.        (spat->spat_short->str_cur < spat->spat_regexp->regmust->str_cur) )){
  1864.         str_free(spat->spat_short);        /* ok if null */
  1865.         spat->spat_short = spat->spat_regexp->regmust;
  1866.         spat->spat_regexp->regmust = Nullstr;
  1867.         spat->spat_flags |= SPAT_SCANFIRST;
  1868.     }
  1869.     }
  1870. }
  1871.  
  1872.  
  1873. char *
  1874. expand_charset(s,len,retlen)
  1875. register char *s;
  1876. int len;
  1877. int *retlen;
  1878. {
  1879.     char t[520];
  1880.     register char *d = t;
  1881.     register int i;
  1882.     register char *send = s + len;
  1883.  
  1884.  
  1885.     while (s < send && d - t <= 256) {
  1886.     if (s[1] == '-' && s+2 < send) {
  1887.         for (i = (s[0] & 0377); i <= (s[2] & 0377); i++)
  1888.         *d++ = i;
  1889.         s += 3;
  1890.     }
  1891.     else
  1892.         *d++ = *s++;
  1893.     }
  1894.     *d = '\0';
  1895.     *retlen = d - t;
  1896.     return nsavestr(t,d-t);
  1897. }
  1898.  
  1899.  
  1900. char *
  1901. scantrans(s)
  1902. register char *s;
  1903. {
  1904.     ARG *arg =
  1905.     l(make_op(O_TRANS,2,stab2arg(A_STAB,defstab),Nullarg,Nullarg));
  1906.     register char *t;
  1907.     register char *r;
  1908.     register short *tbl;
  1909.     register int i;
  1910.     register int j;
  1911.     int tlen, rlen;
  1912.     int squash;
  1913.     int delete;
  1914.     int complement;
  1915.  
  1916.  
  1917.     New(803,tbl,256,short);
  1918.     arg[2].arg_type = A_NULL;
  1919.     arg[2].arg_ptr.arg_cval = (char*) tbl;
  1920.     s = scanstr(s);
  1921.     if (s >= bufend) {
  1922.     yyerror("Translation pattern not terminated");
  1923.     yylval.arg = Nullarg;
  1924.     return s;
  1925.     }
  1926.     t = expand_charset(yylval.arg[1].arg_ptr.arg_str->str_ptr,
  1927.     yylval.arg[1].arg_ptr.arg_str->str_cur,&tlen);
  1928.     arg_free(yylval.arg);
  1929.     s = scanstr(s-1);
  1930.     if (s >= bufend) {
  1931.     yyerror("Translation replacement not terminated");
  1932.     yylval.arg = Nullarg;
  1933.     return s;
  1934.     }
  1935.     complement = delete = squash = 0;
  1936.     while (*s == 'c' || *s == 'd' || *s == 's') {
  1937.     if (*s == 'c')
  1938.         complement = 1;
  1939.     else if (*s == 'd')
  1940.         delete = 2;
  1941.     else
  1942.         squash = 1;
  1943.     s++;
  1944.     }
  1945.     r = expand_charset(yylval.arg[1].arg_ptr.arg_str->str_ptr,
  1946.     yylval.arg[1].arg_ptr.arg_str->str_cur,&rlen);
  1947.     arg_free(yylval.arg);
  1948.     arg[2].arg_len = delete|squash;
  1949.     yylval.arg = arg;
  1950.     if (!rlen && !delete) {
  1951.     Safefree(r);
  1952.     r = t; rlen = tlen;
  1953.     }
  1954.     if (complement) {
  1955.     Zero(tbl, 256, short);
  1956.     for (i = 0; i < tlen; i++)
  1957.         tbl[t[i] & 0377] = -1;
  1958.     for (i = 0, j = 0; i < 256; i++) {
  1959.         if (!tbl[i]) {
  1960.         if (j >= rlen) {
  1961.             if (delete)
  1962.             tbl[i] = -2;
  1963.             else
  1964.             tbl[i] = r[j-1];
  1965.         }
  1966.         else
  1967.             tbl[i] = r[j++];
  1968.         }
  1969.     }
  1970.     }
  1971.     else {
  1972.     for (i = 0; i < 256; i++)
  1973.         tbl[i] = -1;
  1974.     for (i = 0, j = 0; i < tlen; i++,j++) {
  1975.         if (j >= rlen) {
  1976.         if (delete) {
  1977.             if (tbl[t[i] & 0377] == -1)
  1978.             tbl[t[i] & 0377] = -2;
  1979.             continue;
  1980.         }
  1981.         --j;
  1982.         }
  1983.         if (tbl[t[i] & 0377] == -1)
  1984.         tbl[t[i] & 0377] = r[j] & 0377;
  1985.     }
  1986.     }
  1987.     if (r != t)
  1988.     Safefree(r);
  1989.     Safefree(t);
  1990.     return s;
  1991. }
  1992.  
  1993.  
  1994. char *
  1995. scanstr(s)
  1996. register char *s;
  1997. {
  1998.     register char term;
  1999.     register char *d;
  2000.     register ARG *arg;
  2001.     register char *send;
  2002.     register bool makesingle = FALSE;
  2003.     register STAB *stab;
  2004.     bool alwaysdollar = FALSE;
  2005.     bool hereis = FALSE;
  2006.     STR *herewas;
  2007.     STR *str;
  2008.     char *leave = "\\$@nrtfbeacx0123456789[{]}lLuUE"; /* which backslash sequences to keep */
  2009.     int len;
  2010.  
  2011.  
  2012.     arg = op_new(1);
  2013.     yylval.arg = arg;
  2014.     arg->arg_type = O_ITEM;
  2015.  
  2016.  
  2017.     switch (*s) {
  2018.     default:            /* a substitution replacement */
  2019.     arg[1].arg_type = A_DOUBLE;
  2020.     makesingle = TRUE;    /* maybe disable runtime scanning */
  2021.     term = *s;
  2022.     if (term == '\'')
  2023.         leave = Nullch;
  2024.     goto snarf_it;
  2025.     case '0':
  2026.     {
  2027.         unsigned long i;
  2028.         int shift;
  2029.  
  2030.  
  2031.         arg[1].arg_type = A_SINGLE;
  2032.         if (s[1] == 'x') {
  2033.         shift = 4;
  2034.         s += 2;
  2035.         }
  2036.         else if (s[1] == '.')
  2037.         goto decimal;
  2038.         else
  2039.         shift = 3;
  2040.         i = 0;
  2041.         for (;;) {
  2042.         switch (*s) {
  2043.         default:
  2044.             goto out;
  2045.         case '_':
  2046.             s++;
  2047.             break;
  2048.         case '8': case '9':
  2049.             if (shift != 4)
  2050.             yyerror("Illegal octal digit");
  2051.             /* FALL THROUGH */
  2052.         case '0': case '1': case '2': case '3': case '4':
  2053.         case '5': case '6': case '7':
  2054.             i <<= shift;
  2055.             i += *s++ & 15;
  2056.             break;
  2057.         case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
  2058.         case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
  2059.             if (shift != 4)
  2060.             goto out;
  2061.             i <<= 4;
  2062.             i += (*s++ & 7) + 9;
  2063.             break;
  2064.         }
  2065.         }
  2066.       out:
  2067.         str = Str_new(92,0);
  2068.         str_numset(str,(double)i);
  2069.         if (str->str_ptr) {
  2070.         Safefree(str->str_ptr);
  2071.         str->str_ptr = Nullch;
  2072.         str->str_len = str->str_cur = 0;
  2073.         }
  2074.         arg[1].arg_ptr.arg_str = str;
  2075.     }
  2076.     break;
  2077.     case '1': case '2': case '3': case '4': case '5':
  2078.     case '6': case '7': case '8': case '9': case '.':
  2079.       decimal:
  2080.     arg[1].arg_type = A_SINGLE;
  2081.     d = tokenbuf;
  2082.     while (isDIGIT(*s) || *s == '_') {
  2083.         if (*s == '_')
  2084.         s++;
  2085.         else
  2086.         *d++ = *s++;
  2087.     }
  2088.     if (*s == '.' && s[1] && index("0123456789eE ;",s[1])) {
  2089.         *d++ = *s++;
  2090.         while (isDIGIT(*s) || *s == '_') {
  2091.         if (*s == '_')
  2092.             s++;
  2093.         else
  2094.             *d++ = *s++;
  2095.         }
  2096.     }
  2097.     if (*s && index("eE",*s) && index("+-0123456789",s[1])) {
  2098.         *d++ = *s++;
  2099.         if (*s == '+' || *s == '-')
  2100.         *d++ = *s++;
  2101.         while (isDIGIT(*s))
  2102.         *d++ = *s++;
  2103.     }
  2104.     *d = '\0';
  2105.     str = Str_new(92,0);
  2106.     str_numset(str,atof(tokenbuf));
  2107.     if (str->str_ptr) {
  2108.         Safefree(str->str_ptr);
  2109.         str->str_ptr = Nullch;
  2110.         str->str_len = str->str_cur = 0;
  2111.     }
  2112.     arg[1].arg_ptr.arg_str = str;
  2113.     break;
  2114.     case '<':
  2115.     if (*++s == '<') {
  2116.         hereis = TRUE;
  2117.         d = tokenbuf;
  2118.         if (!rsfp)
  2119.         *d++ = '\n';
  2120.         if (*++s && index("`'\"",*s)) {
  2121.         term = *s++;
  2122.         s = cpytill(d,s,bufend,term,&len);
  2123.         if (s < bufend)
  2124.             s++;
  2125.         d += len;
  2126.         }
  2127.         else {
  2128.         if (*s == '\\')
  2129.             s++, term = '\'';
  2130.         else
  2131.             term = '"';
  2132.         while (isALNUM(*s))
  2133.             *d++ = *s++;
  2134.         }                /* assuming tokenbuf won't clobber */
  2135.         *d++ = '\n';
  2136.         *d = '\0';
  2137.         len = d - tokenbuf;
  2138.         d = "\n";
  2139.         if (rsfp || !(d=ninstr(s,bufend,d,d+1)))
  2140.         herewas = str_make(s,bufend-s);
  2141.         else
  2142.         s--, herewas = str_make(s,d-s);
  2143.         s += herewas->str_cur;
  2144.         if (term == '\'')
  2145.         goto do_single;
  2146.         if (term == '`')
  2147.         goto do_back;
  2148.         goto do_double;
  2149.     }
  2150.     d = tokenbuf;
  2151.     s = cpytill(d,s,bufend,'>',&len);
  2152.     if (s < bufend)
  2153.         s++;
  2154.     if (*d == '$') d++;
  2155.     while (*d && (isALNUM(*d) || *d == '\''))
  2156.         d++;
  2157.     if (d - tokenbuf != len) {
  2158.         d = tokenbuf;
  2159.         arg[1].arg_type = A_GLOB;
  2160.         d = nsavestr(d,len);
  2161.         arg[1].arg_ptr.arg_stab = stab = genstab();
  2162.         stab_io(stab) = stio_new();
  2163.         stab_val(stab) = str_make(d,len);
  2164.         Safefree(d);
  2165.         set_csh();
  2166.     }
  2167.     else {
  2168.         d = tokenbuf;
  2169.         if (!len)
  2170.         (void)strcpy(d,"ARGV");
  2171.         if (*d == '$') {
  2172.         arg[1].arg_type = A_INDREAD;
  2173.         arg[1].arg_ptr.arg_stab = stabent(d+1,TRUE);
  2174.         }
  2175.         else {
  2176.         arg[1].arg_type = A_READ;
  2177.         arg[1].arg_ptr.arg_stab = stabent(d,TRUE);
  2178.         if (!stab_io(arg[1].arg_ptr.arg_stab))
  2179.             stab_io(arg[1].arg_ptr.arg_stab) = stio_new();
  2180.         if (strEQ(d,"ARGV")) {
  2181.             (void)aadd(arg[1].arg_ptr.arg_stab);
  2182.             stab_io(arg[1].arg_ptr.arg_stab)->flags |=
  2183.               IOF_ARGV|IOF_START;
  2184.         }
  2185.         }
  2186.     }
  2187.     break;
  2188.  
  2189.  
  2190.     case 'q':
  2191.     s++;
  2192.     if (*s == 'q') {
  2193.         s++;
  2194.         goto do_double;
  2195.     }
  2196.     if (*s == 'x') {
  2197.         s++;
  2198.         goto do_back;
  2199.     }
  2200.     /* FALL THROUGH */
  2201.     case '\'':
  2202.       do_single:
  2203.     term = *s;
  2204.     arg[1].arg_type = A_SINGLE;
  2205.     leave = Nullch;
  2206.     goto snarf_it;
  2207.  
  2208.  
  2209.     case '"':
  2210.       do_double:
  2211.     term = *s;
  2212.     arg[1].arg_type = A_DOUBLE;
  2213.     makesingle = TRUE;    /* maybe disable runtime scanning */
  2214.     alwaysdollar = TRUE;    /* treat $) and $| as variables */
  2215.     goto snarf_it;
  2216.     case '`':
  2217.       do_back:
  2218.     term = *s;
  2219.     arg[1].arg_type = A_BACKTICK;
  2220.     set_csh();
  2221.     alwaysdollar = TRUE;    /* treat $) and $| as variables */
  2222.       snarf_it:
  2223.     {
  2224.         STR *tmpstr;
  2225.         char *tmps;
  2226.  
  2227.  
  2228.         CLINE;
  2229.         multi_start = curcmd->c_line;
  2230.         if (hereis)
  2231.         multi_open = multi_close = '<';
  2232.         else {
  2233.         multi_open = term;
  2234.         if (term && (tmps = index("([{< )]}> )]}>",term)))
  2235.             term = tmps[5];
  2236.         multi_close = term;
  2237.         }
  2238.         tmpstr = Str_new(87,80);
  2239.         if (hereis) {
  2240.         term = *tokenbuf;
  2241.         if (!rsfp) {
  2242.             d = s;
  2243.             while (s < bufend &&
  2244.               (*s != term || bcmp(s,tokenbuf,len) != 0) ) {
  2245.             if (*s++ == '\n')
  2246.                 curcmd->c_line++;
  2247.             }
  2248.             if (s >= bufend) {
  2249.             curcmd->c_line = multi_start;
  2250.             fatal("EOF in string");
  2251.             }
  2252.             str_nset(tmpstr,d+1,s-d);
  2253.             s += len - 1;
  2254.             str_ncat(herewas,s,bufend-s);
  2255.             str_replace(linestr,herewas);
  2256.             oldoldbufptr = oldbufptr = bufptr = s = str_get(linestr);
  2257.             bufend = linestr->str_ptr + linestr->str_cur;
  2258.             hereis = FALSE;
  2259.         }
  2260.         else
  2261.             str_nset(tmpstr,"",0);   /* avoid "uninitialized" warning */
  2262.         }
  2263.         else
  2264.         s = str_append_till(tmpstr,s+1,bufend,term,leave);
  2265.         while (s >= bufend) {    /* multiple line string? */
  2266.         if (!rsfp ||
  2267.          !(oldoldbufptr = oldbufptr = s = str_gets(linestr, rsfp, 0))) {
  2268.             curcmd->c_line = multi_start;
  2269.             fatal("EOF in string");
  2270.         }
  2271.         curcmd->c_line++;
  2272.         if (perldb) {
  2273.             STR *str = Str_new(88,0);
  2274.  
  2275.  
  2276.             str_sset(str,linestr);
  2277.             astore(stab_xarray(curcmd->c_filestab),
  2278.               (int)curcmd->c_line,str);
  2279.         }
  2280.         bufend = linestr->str_ptr + linestr->str_cur;
  2281.         if (hereis) {
  2282.             if (*s == term && bcmp(s,tokenbuf,len) == 0) {
  2283.             s = bufend - 1;
  2284.             *s = ' ';
  2285.             str_scat(linestr,herewas);
  2286.             bufend = linestr->str_ptr + linestr->str_cur;
  2287.             }
  2288.             else {
  2289.             s = bufend;
  2290.             str_scat(tmpstr,linestr);
  2291.             }
  2292.         }
  2293.         else
  2294.             s = str_append_till(tmpstr,s,bufend,term,leave);
  2295.         }
  2296.         multi_end = curcmd->c_line;
  2297.         s++;
  2298.         if (tmpstr->str_cur + 5 < tmpstr->str_len) {
  2299.         tmpstr->str_len = tmpstr->str_cur + 1;
  2300.         Renew(tmpstr->str_ptr, tmpstr->str_len, char);
  2301.         }
  2302.         if ((arg[1].arg_type & A_MASK) == A_SINGLE) {
  2303.         arg[1].arg_ptr.arg_str = tmpstr;
  2304.         break;
  2305.         }
  2306.         tmps = s;
  2307.         s = tmpstr->str_ptr;
  2308.         send = s + tmpstr->str_cur;
  2309.         while (s < send) {        /* see if we can make SINGLE */
  2310.         if (*s == '\\' && s[1] && isDIGIT(s[1]) && !isDIGIT(s[2]) &&
  2311.           !alwaysdollar && s[1] != '0')
  2312.             *s = '$';        /* grandfather \digit in subst */
  2313.         if ((*s == '$' || *s == '@') && s+1 < send &&
  2314.           (alwaysdollar || (s[1] != ')' && s[1] != '|'))) {
  2315.             makesingle = FALSE;    /* force interpretation */
  2316.         }
  2317.         else if (*s == '\\' && s+1 < send) {
  2318.             if (index("lLuUE",s[1]))
  2319.             makesingle = FALSE;
  2320.             s++;
  2321.         }
  2322.         s++;
  2323.         }
  2324.         s = d = tmpstr->str_ptr;    /* assuming shrinkage only */
  2325.         while (s < send) {
  2326.         if ((*s == '$' && s+1 < send &&
  2327.             (alwaysdollar || /*(*/ (s[1] != ')' && s[1] != '|')) ) ||
  2328.             (*s == '@' && s+1 < send) ) {
  2329.             if (s[1] == '#' && (isALPHA(s[2]) || s[2] == '_'))
  2330.             *d++ = *s++;
  2331.             len = scanident(s,send,tokenbuf) - s;
  2332.             if (*s == '$' || strEQ(tokenbuf,"ARGV")
  2333.               || strEQ(tokenbuf,"ENV")
  2334.               || strEQ(tokenbuf,"SIG")
  2335.               || strEQ(tokenbuf,"INC") )
  2336.             (void)stabent(tokenbuf,TRUE); /* make sure it exists */
  2337.             while (len--)
  2338.             *d++ = *s++;
  2339.             continue;
  2340.         }
  2341.         else if (*s == '\\' && s+1 < send) {
  2342.             s++;
  2343.             switch (*s) {
  2344.             default:
  2345.             if (!makesingle && (!leave || (*s && index(leave,*s))))
  2346.                 *d++ = '\\';
  2347.             *d++ = *s++;
  2348.             continue;
  2349.             case '0': case '1': case '2': case '3':
  2350.             case '4': case '5': case '6': case '7':
  2351.             *d++ = scanoct(s, 3, &len);
  2352.             s += len;
  2353.             continue;
  2354.             case 'x':
  2355.             *d++ = scanhex(++s, 2, &len);
  2356.             s += len;
  2357.             continue;
  2358.             case 'c':
  2359.             s++;
  2360.             *d = *s++;
  2361.             if (isLOWER(*d))
  2362.                 *d = toupper(*d);
  2363.             *d++ ^= 64;
  2364.             continue;
  2365.             case 'b':
  2366.             *d++ = '\b';
  2367.             break;
  2368.             case 'n':
  2369.             *d++ = '\n';
  2370.             break;
  2371.             case 'r':
  2372.             *d++ = '\r';
  2373.             break;
  2374.             case 'f':
  2375.             *d++ = '\f';
  2376.             break;
  2377.             case 't':
  2378.             *d++ = '\t';
  2379.             break;
  2380.             case 'e':
  2381.             *d++ = '\033';
  2382.             break;
  2383.             case 'a':
  2384.             *d++ = '\007';
  2385.             break;
  2386.             }
  2387.             s++;
  2388.             continue;
  2389.         }
  2390.         *d++ = *s++;
  2391.         }
  2392.         *d = '\0';
  2393.  
  2394.  
  2395.         if ((arg[1].arg_type & A_MASK) == A_DOUBLE && makesingle)
  2396.             arg[1].arg_type = A_SINGLE;    /* now we can optimize on it */
  2397.  
  2398.  
  2399.         tmpstr->str_cur = d - tmpstr->str_ptr;
  2400.         arg[1].arg_ptr.arg_str = tmpstr;
  2401.         s = tmps;
  2402.         break;
  2403.     }
  2404.     }
  2405.     if (hereis)
  2406.     str_free(herewas);
  2407.     return s;
  2408. }
  2409.  
  2410.  
  2411. FCMD *
  2412. load_format()
  2413. {
  2414.     FCMD froot;
  2415.     FCMD *flinebeg;
  2416.     char *eol;
  2417.     register FCMD *fprev = &froot;
  2418.     register FCMD *fcmd;
  2419.     register char *s;
  2420.     register char *t;
  2421.     register STR *str;
  2422.     bool noblank;
  2423.     bool repeater;
  2424.  
  2425.  
  2426.     Zero(&froot, 1, FCMD);
  2427.     s = bufptr;
  2428.     while (s < bufend || (rsfp && (s = str_gets(linestr,rsfp, 0)) != Nullch)) {
  2429.     curcmd->c_line++;
  2430.     if (in_eval && !rsfp) {
  2431.         eol = index(s,'\n');
  2432.         if (!eol++)
  2433.         eol = bufend;
  2434.     }
  2435.     else
  2436.         eol = bufend = linestr->str_ptr + linestr->str_cur;
  2437.     if (perldb) {
  2438.         STR *tmpstr = Str_new(89,0);
  2439.  
  2440.  
  2441.         str_nset(tmpstr, s, eol-s);
  2442.         astore(stab_xarray(curcmd->c_filestab), (int)curcmd->c_line,tmpstr);
  2443.     }
  2444.     if (*s == '.') {
  2445.         /*SUPPRESS 530*/
  2446.         for (t = s+1; *t == ' ' || *t == '\t'; t++) ;
  2447.         if (*t == '\n') {
  2448.         bufptr = s;
  2449.         return froot.f_next;
  2450.         }
  2451.     }
  2452.     if (*s == '#') {
  2453.         s = eol;
  2454.         continue;
  2455.     }
  2456.     flinebeg = Nullfcmd;
  2457.     noblank = FALSE;
  2458.     repeater = FALSE;
  2459.     while (s < eol) {
  2460.         Newz(804,fcmd,1,FCMD);
  2461.         fprev->f_next = fcmd;
  2462.         fprev = fcmd;
  2463.         for (t=s; t < eol && *t != '@' && *t != '^'; t++) {
  2464.         if (*t == '~') {
  2465.             noblank = TRUE;
  2466.             *t = ' ';
  2467.             if (t[1] == '~') {
  2468.             repeater = TRUE;
  2469.             t[1] = ' ';
  2470.             }
  2471.         }
  2472.         }
  2473.         fcmd->f_pre = nsavestr(s, t-s);
  2474.         fcmd->f_presize = t-s;
  2475.         s = t;
  2476.         if (s >= eol) {
  2477.         if (noblank)
  2478.             fcmd->f_flags |= FC_NOBLANK;
  2479.         if (repeater)
  2480.             fcmd->f_flags |= FC_REPEAT;
  2481.         break;
  2482.         }
  2483.         if (!flinebeg)
  2484.         flinebeg = fcmd;        /* start values here */
  2485.         if (*s++ == '^')
  2486.         fcmd->f_flags |= FC_CHOP;    /* for doing text filling */
  2487.         switch (*s) {
  2488.         case '*':
  2489.         fcmd->f_type = F_LINES;
  2490.         *s = '\0';
  2491.         break;
  2492.         case '<':
  2493.         fcmd->f_type = F_LEFT;
  2494.         while (*s == '<')
  2495.             s++;
  2496.         break;
  2497.         case '>':
  2498.         fcmd->f_type = F_RIGHT;
  2499.         while (*s == '>')
  2500.             s++;
  2501.         break;
  2502.         case '|':
  2503.         fcmd->f_type = F_CENTER;
  2504.         while (*s == '|')
  2505.             s++;
  2506.         break;
  2507.         case '#':
  2508.         case '.':
  2509.         /* Catch the special case @... and handle it as a string
  2510.            field. */
  2511.         if (*s == '.' && s[1] == '.') {
  2512.             goto default_format;
  2513.         }
  2514.         fcmd->f_type = F_DECIMAL;
  2515.         {
  2516.             char *p;
  2517.  
  2518.  
  2519.             /* Read a format in the form @####.####, where either group
  2520.                of ### may be empty, or the final .### may be missing. */
  2521.             while (*s == '#')
  2522.             s++;
  2523.             if (*s == '.') {
  2524.             s++;
  2525.             p = s;
  2526.             while (*s == '#')
  2527.                 s++;
  2528.             fcmd->f_decimals = s-p;
  2529.             fcmd->f_flags |= FC_DP;
  2530.             } else {
  2531.             fcmd->f_decimals = 0;
  2532.             }
  2533.         }
  2534.         break;
  2535.         default:
  2536.         default_format:
  2537.         fcmd->f_type = F_LEFT;
  2538.         break;
  2539.         }
  2540.         if (fcmd->f_flags & FC_CHOP && *s == '.') {
  2541.         fcmd->f_flags |= FC_MORE;
  2542.         while (*s == '.')
  2543.             s++;
  2544.         }
  2545.         fcmd->f_size = s-t;
  2546.     }
  2547.     if (flinebeg) {
  2548.       again:
  2549.         if (s >= bufend &&
  2550.           (!rsfp || (s = str_gets(linestr, rsfp, 0)) == Nullch) )
  2551.         goto badform;
  2552.         curcmd->c_line++;
  2553.         if (in_eval && !rsfp) {
  2554.         eol = index(s,'\n');
  2555.         if (!eol++)
  2556.             eol = bufend;
  2557.         }
  2558.         else
  2559.         eol = bufend = linestr->str_ptr + linestr->str_cur;
  2560.         if (perldb) {
  2561.         STR *tmpstr = Str_new(90,0);
  2562.  
  2563.  
  2564.         str_nset(tmpstr, s, eol-s);
  2565.         astore(stab_xarray(curcmd->c_filestab),
  2566.             (int)curcmd->c_line,tmpstr);
  2567.         }
  2568.         if (strnEQ(s,".\n",2)) {
  2569.         bufptr = s;
  2570.         yyerror("Missing values line");
  2571.         return froot.f_next;
  2572.         }
  2573.         if (*s == '#') {
  2574.         s = eol;
  2575.         goto again;
  2576.         }
  2577.         str = flinebeg->f_unparsed = Str_new(91,eol - s);
  2578.         str->str_u.str_hash = curstash;
  2579.         str_nset(str,"(",1);
  2580.         flinebeg->f_line = curcmd->c_line;
  2581.         eol[-1] = '\0';
  2582.         if (!flinebeg->f_next->f_type || index(s, ',')) {
  2583.         eol[-1] = '\n';
  2584.         str_ncat(str, s, eol - s - 1);
  2585.         str_ncat(str,",$$);",5);
  2586.         s = eol;
  2587.         }
  2588.         else {
  2589.         eol[-1] = '\n';
  2590.         while (s < eol && isSPACE(*s))
  2591.             s++;
  2592.         t = s;
  2593.         while (s < eol) {
  2594.             switch (*s) {
  2595.             case ' ': case '\t': case '\n': case ';':
  2596.             str_ncat(str, t, s - t);
  2597.             str_ncat(str, "," ,1);
  2598.             while (s < eol && (isSPACE(*s) || *s == ';'))
  2599.                 s++;
  2600.             t = s;
  2601.             break;
  2602.             case '$':
  2603.             str_ncat(str, t, s - t);
  2604.             t = s;
  2605.             s = scanident(s,eol,tokenbuf);
  2606.             str_ncat(str, t, s - t);
  2607.             t = s;
  2608.             if (s < eol && *s && index("$'\"",*s))
  2609.                 str_ncat(str, ",", 1);
  2610.             break;
  2611.             case '"': case '\'':
  2612.             str_ncat(str, t, s - t);
  2613.             t = s;
  2614.             s++;
  2615.             while (s < eol && (*s != *t || s[-1] == '\\'))
  2616.                 s++;
  2617.             if (s < eol)
  2618.                 s++;
  2619.             str_ncat(str, t, s - t);
  2620.             t = s;
  2621.             if (s < eol && *s && index("$'\"",*s))
  2622.                 str_ncat(str, ",", 1);
  2623.             break;
  2624.             default:
  2625.             yyerror("Please use commas to separate fields");
  2626.             }
  2627.         }
  2628.         str_ncat(str,"$$);",4);
  2629.         }
  2630.     }
  2631.     }
  2632.   badform:
  2633.     bufptr = str_get(linestr);
  2634.     yyerror("Format not terminated");
  2635.     return froot.f_next;
  2636. }
  2637.  
  2638.  
  2639. set_csh()
  2640. {
  2641. #ifdef CSH
  2642.     if (!cshlen)
  2643.     cshlen = strlen(cshname);
  2644. #endif
  2645. }
  2646.